package com.xuzz.study.io.nio.groupchat;

import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class GroupChatServer {
    Selector selector;
    ServerSocketChannel listenChannel;
    static final int PORT= 6667;

    //初始化工作
    public GroupChatServer(){
        try
        {
            selector = Selector.open();
            listenChannel = ServerSocketChannel.open();
            listenChannel.socket().bind(new InetSocketAddress(PORT));
            listenChannel.configureBlocking(false);
            listenChannel.register(selector, SelectionKey.OP_ACCEPT);
        }catch (IOException ex){
            ex.printStackTrace();
        }
    }

    public void listen(){
        try
        {
            while(true)
            {
                int count =selector.select(2000);
                if(count>0)
                {
                    //说明有事件要处理。
                    //判断到底是什么事件？
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
                    while(keyIterator.hasNext())
                    {
                        SelectionKey key = keyIterator.next();
                        //到底是什么事件？
                        if(key.isAcceptable())
                        {
                            //如果是连接事件，那说明ServerSocketChannel得到了连接
                            SocketChannel socketChannel = listenChannel.accept();
                            socketChannel.configureBlocking(false);
                            socketChannel.register(selector,SelectionKey.OP_READ);
                            sendInfoToOtherClients(socketChannel.getRemoteAddress()+" 上线了",socketChannel);
                        }
                        if(key.isReadable())
                        {
                            //如果是可读事件
                            readData(key);
                        }

                        selectionKeys.remove(key);
                    }

                }
                else
                {
                    //System.out.println("等待中");
                }
            }
        }
        catch (Exception ex){
            ex.printStackTrace();
        }
        finally {

        }
    }

    //读取客户端消息
    private void readData(SelectionKey key)
    {
        SocketChannel channel = null;
        try {
            //取到关联的通道
            channel = (SocketChannel)key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int count = channel.read(buffer);
            if(count>0)
            {
                //把缓冲区里的转成字符串
                String msg = new String(buffer.array());
                //输出该消息
                System.out.println(
                        String.format("%s",
                                msg)
                );

                //向其他的客户端转发
                sendInfoToOtherClients(msg,channel);
            }
        }
        catch (IOException e)
        {
            try
            {
                System.out.println(channel.getRemoteAddress()+" 离线了...");

                //取消注册
                key.cancel();
                channel.close();
            }
            catch (IOException e2)
            {
                e2.printStackTrace();
            }
        }
    }

    private void sendInfoToOtherClients(String msg,SocketChannel self) throws IOException{
        System.out.println("服务器转发消息中...");
        //遍历所有注册到selector上的channel，并排除自己
        for(SelectionKey key:selector.keys())
        {
            Channel target = key.channel();

            //排除自己
            if(target instanceof SocketChannel && target!= self)
            {
                SocketChannel socketChannel = (SocketChannel)target;

                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());

                socketChannel.write(buffer);
            }
        }
    }

    public static void main(String[] args) {
        GroupChatServer groupChatServer=new GroupChatServer();
        groupChatServer.listen();
    }
}
